﻿
using System;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Input;

using FXnaEngine.Input;



namespace FXnaEngine.Components
{


     public class FFreeCameraComponent:FInputComponent
    {


         public FFreeCameraComponent(FEntity parent):base(parent)
         {

 
         }




        /// <summary>
        /// Speed modifier to determine how much movement is sent to the parent entity.
        /// </summary>
        private float speed = 100.0f;

        /// <summary>
        /// Speed is multiplied by this amount when the player holds down the left mouse button.
        /// </summary>
        private int turboSpeedModifier = 4;





        public override void Initialize()
        {
            base.Initialize();

            InitButtonListeners();


        }




        /// <summary>
        /// Initialize button listeners. This determines which buttons the input poller will listen for
        /// </summary>
        public void InitButtonListeners()
        {
            this.inputs = new InputPollingHandler(this.parentEntity.Game);



            this.inputs.AddInputListener(Keys.Up);
            this.inputs.AddInputListener(Keys.Down);
            this.inputs.AddInputListener(Keys.Left);
            this.inputs.AddInputListener(Keys.Right);
            this.inputs.AddInputListener(Keys.W);
            this.inputs.AddInputListener(Keys.S);
            this.inputs.AddInputListener(Keys.A);
            this.inputs.AddInputListener(Keys.D);
            this.inputs.AddInputListener(Keys.Q);
            this.inputs.AddInputListener(Keys.E);




        }



        public override bool ExecuteMessage(IMessage message)
        {


            switch (message.Type)
            {
                case MessageType.MouseDown:
                    {
                        MsgMouseButtonPressed mouseDownMessage = message as MsgMouseButtonPressed;
                        message.TypeCheck(mouseDownMessage);

                        if (mouseDownMessage.Button == MouseButton.Left)
                            this.speed *= this.turboSpeedModifier;
                    }
                    return true;

                case MessageType.MouseUp:
                    {
                        MsgMouseButtonReleased mouseUpMessage = message as MsgMouseButtonReleased;
                        message.TypeCheck(mouseUpMessage);

                        if (mouseUpMessage.Button == MouseButton.Left)
                            this.speed *= (1.0f / this.turboSpeedModifier);
                    }
                    return true;

                case MessageType.MouseScroll:
                    {
                        MsgMouseScroll scrollWheelMessage = message as MsgMouseScroll;
                        message.TypeCheck(scrollWheelMessage);

                        HandleMouseScroll(scrollWheelMessage.ScrollWheelDelta);
                    }
                    return true;

                case MessageType.MouseMove:
                    {
                        MsgMouseMove moveMessage = message as MsgMouseMove;
                        message.TypeCheck(moveMessage);

                        HandleMouseMove(moveMessage.PositionDelta);
                    }
                    return true;

                default:
                    return false;
            }


            return false;
        }


        /// <summary>
        /// This is the component's Update loop, it takes care of placing and moving the camera each frame.
        /// </summary>
        /// <param name="gameTime">XNA's built-in timer, provides a snapshot of the game's time.</param>
        public override void Update(GameTime gameTime)
        {
            //if (!this.parentEntity.Game.IsMouseVisible)
            //{
            //    ProcessInput(gameTime);
            //}


            //测试暂时去除这部分限制

            ProcessInput(gameTime);


        }


        /// <summary>
        /// Handles mouse scroll wheel. This camera zooms based on mouse scrolling
        /// </summary>
        /// <param name="distance">Amount mouse scroll wheel has moved</param>
        private void HandleMouseScroll(int distance)
        {

            this.parentEntity.Transform.Walk(distance);

            



            //if (distance > 0)
            //{
            //    MsgCameraZoomIn camZoomMsg = ObjectPool.Aquire<MsgCameraZoomIn>();
            //    camZoomMsg.UniqueTarget = this.parentEntity.UniqueID;
            //    this.parentEntity.Game.SendMessage(camZoomMsg);
            //}
            //else
            //{
            //    MsgCameraZoomOut camZoomMsg = ObjectPool.Aquire<MsgCameraZoomOut>();
            //    camZoomMsg.UniqueTarget = this.parentEntity.UniqueID;
            //    this.parentEntity.Game.SendMessage(camZoomMsg);
            //}
        }

        /// <summary>
        /// Handles mouse movement
        /// </summary>
        /// <param name="distance">Distance mouse has moved, in each direction (X and Y).</param>
        private void HandleMouseMove(Vector2 distance)
        {
            int invertMod =  -1 ;

            this.parentEntity.Transform.Pitch(distance.Y * invertMod);



           
           

            // If the camera is not upside down
            if (this.parentEntity.Transform.Orientation.Up.Y > 0.0f)
            {
                this.parentEntity.Transform.YawAroundWorldUp(-distance.X);
            }
            else // If the camera is upside down reverse the rotation direction
            {
                this.parentEntity.Transform.YawAroundWorldUp(distance.X);
            }
        }

        /// <summary>
        /// Process camera movements based on input
        /// </summary>
        /// <param name="gameTime">Snapshot of the timers</param>
        private void ProcessInput(GameTime gameTime)
        {

            float timeDelta = this.parentEntity.Game.PartialSecondsThisFrame;

            if (this.inputs.IsDown(Keys.Up))
            {
                this.parentEntity.Transform.Pitch(timeDelta);
            }

            if (this.inputs.IsDown(Keys.Down))
            {
                this.parentEntity.Transform.Pitch(-timeDelta);
            }

            if (this.inputs.IsDown(Keys.Left))
            {
                this.parentEntity.Transform.YawAroundWorldUp(timeDelta);
            }

            if (this.inputs.IsDown(Keys.Right))
            {
                this.parentEntity.Transform.YawAroundWorldUp(-timeDelta);
            }

            if (this.inputs.IsDown(Keys.W))
            {
                this.parentEntity.Transform.Walk(timeDelta * this.speed);
            }

            if (this.inputs.IsDown(Keys.S))
            {
                this.parentEntity.Transform.Walk(timeDelta * -this.speed);
            }

            if (this.inputs.IsDown(Keys.A))
            {
                this.parentEntity.Transform.Strafe(timeDelta * -this.speed);
            }

            if (this.inputs.IsDown(Keys.D))
            {
                this.parentEntity.Transform.Strafe(timeDelta * this.speed);
            }

            if (this.inputs.IsDown(Keys.Q))
            {
                this.parentEntity.Transform.Roll(-timeDelta);
            }

            if (this.inputs.IsDown(Keys.E))
            {
                this.parentEntity.Transform.Roll(timeDelta);
            }



        }


        



    }
}
